



import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.PriorityQueue;
import java.util.Scanner;


public class Operator {
	public ArrayList<StringList> find(String regEx, String fileName){
		RegexScanner a = new RegexScanner(fileName, regEx);
		
		
		return a.getStringlists();
	}
	public ArrayList<StringList> inters(ArrayList<StringList> list1, ArrayList<StringList> list2){
		ArrayList<StringList> inters = new ArrayList<StringList>();
		for(int i = 0;i<list1.size();i++){

			for(int j = 0; j<list2.size();j++){
				if(list1.get(i).value.equals(list2.get(j).value)){
					if(!(inters.contains(list1.get(i)))){
						inters.add(list1.get(i));
						for(int k = 0;k<list2.get(0).data.size();k++){

							inters.get(inters.size()-1).getData().add(list2.get(j).data.get(k));
						}

					}
				}
			}
		}
		if(inters.size()>0){
			return inters;
		}
		
		return null;
	}
	public ArrayList<StringList> union(ArrayList<StringList> list1, ArrayList<StringList> list2){
		ArrayList<StringList> inters = new ArrayList<StringList>();
		HashMap<String,Integer> check = new HashMap<String,Integer>();
		for(int i = 0;i<list1.size();i++){
			
			for(int j = 0; j<list2.size();j++){
				if(list1.get(i).value.equals(list2.get(j).value)){
					if(!(inters.contains(list1.get(i)))){
						inters.add(list1.get(i));
						check.put(list1.get(i).value, 1);
						for(int k = 0;k<list2.get(0).data.size();k++){
							
							inters.get(inters.size()-1).getData().add(list2.get(j).data.get(k));
						}
						
					}
				} else {
					if(!(check.containsKey(list1.get(i).value))){
						inters.add(list1.get(i));
						check.put(list1.get(i).value, 1);
						
					}
					if(!(check.containsKey(list2.get(j).value))){
						inters.add(list2.get(j));
						check.put(list2.get(j).value, 1);
						
					}
				}
				
			}
		}
		if(inters.size()>0){
			return inters;
		}
		return null;
	}
	public ArrayList<StringList> difference(ArrayList<StringList> list1, ArrayList<StringList> list2){
		ArrayList<StringList> inters = new ArrayList<StringList>();
		HashMap<String,Integer> check = new HashMap<String,Integer>();
		HashMap<String,Integer> minus = new HashMap<String,Integer>();
		for(int i = 0;i<list1.size();i++){
			
			for(int j = 0; j<list2.size();j++){
				if((list1.get(i).value.equals(list2.get(j).value))){
					if(!(inters.contains(list1.get(i)))){
						minus.put(list1.get(i).value, 1);
						
						
					}
				} else {
					if(!(check.containsKey(list1.get(i).value)) && !(minus.containsKey(list1.get(i).value))){
						inters.add(list1.get(i));
						check.put(list1.get(i).value, 1);
						
					}
					if(!(check.containsKey(list2.get(j).value)) && !(minus.containsKey(list2.get(j).value))){
						inters.add(list2.get(j));
						check.put(list2.get(j).value, 1);
						
					}
				}
				
			}
		}
		if(inters.size()>0){
			return inters;
		}
		return null;
	}
	public void print(int var){
		System.out.println(var);
	}
	public void print(ArrayList<StringList> var){
		for(int i = 0;i<var.size();i++){
			String print = "String: \"" +var.get(i).value+"\"";
			for(int j = 0; j<var.get(i).data.size();j++){
				print=print+" <Filename: " + var.get(i).data.get(j).fileName+" , Start Index: " + var.get(i).data.get(j).startIndex+">";
			}
			System.out.println(print);
		}
	}
	public void recursiveReplace(String regEx, String replaceWith, String source, String destination){
		if(source.equals(destination)){
			throw new Error("Parser Error: source filename is same as destination filename");
		}
		recursiveReplace(regEx, replaceWith, source, destination,true);
	}
	private String recursiveReplace(String regEx, String replaceWith,
			String source, String destination,boolean conditionCheck) {
		
		ArrayList<StringList> match =find(regEx, source);
		if(match.size()==0){
			
			return null;
		}
		boolean test =true;
		for(int i = 0;i<match.size();i++){
			if(!(match.get(i).value.equals(replaceWith))){
				test = false;
			}
		}
		if (test == true){
			return null;
		}
		HashMap<String, ArrayList<StringList>> matches = new HashMap<String, ArrayList<StringList>>();
		for(int i =0;i<match.size();i++){
			for(int j =0;j<match.get(i).data.size();j++){
				if(!(matches.containsKey(match.get(i).data.get(j).line))){
					ArrayList<StringList> temp = new ArrayList<StringList>();
					temp.add(match.get(i));
					matches.put(match.get(i).data.get(j).line, temp);
				} else {
					matches.get(match.get(i).data.get(j).line).add(match.get(i));
				}
			}
		}

		Scanner input;
		String stringBuffer ="";
		try{
			// Open the file that is the first 
			// command line parameter
			FileInputStream fstream = new FileInputStream(source);
			// Get the object of DataInputStream
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			//Read File Line By Line
			int line = 0;
			while ((strLine = br.readLine()) != null)   {
				line++;
				if(matches.containsKey(""+line)){
					PriorityQueue<String> startIndex = new PriorityQueue<String>();
					PriorityQueue<String> endIndex = new PriorityQueue<String>();
					for(StringList a:matches.get(""+line)){
						for(Data b:a.data){
							startIndex.add(b.startIndex);
							endIndex.add(b.endIndex);
						}
					}

					for(int i = 0;i<strLine.length();i++){
						if(startIndex.peek().equals(""+i)){
							stringBuffer=stringBuffer+replaceWith;
							startIndex.poll();
							i=Integer.parseInt(endIndex.poll());
						} else {
							stringBuffer=stringBuffer+strLine.charAt(i);
						}
					}
				} else {
					input = new Scanner(strLine);
					boolean check = false;
					while(input.hasNext()) {
						if(check){
							stringBuffer=stringBuffer+" ";

						} else {
							check = true;
						}
						stringBuffer=stringBuffer+input.next();
					}
				}

				stringBuffer=stringBuffer+"\n";
			}

			//Close the input stream
			in.close();
		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}


		try{
			// Create file 
			File name = new File(destination);
			if(name.exists()){
				name.delete();
			}
			FileWriter fstream = new FileWriter(name,true);

			BufferedWriter output = new BufferedWriter(fstream);

			for(int i = 0;i<stringBuffer.length();i++){
				if((int)stringBuffer.charAt(i)=='\n'){
					output.newLine();
				} else{
					output.write(""+stringBuffer.charAt(i));
				}


			}
			//Close the output stream
			output.close();
		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}
		recursiveReplace(regEx, replaceWith, destination, destination);
		return null;
		
	}
	public void replace(String regEx, String replaceWith, String source, String destination){
		if(source.equals(destination)){
			throw new Error("Parser Error: source filename is same as destination filename");
		}
		ArrayList<StringList> match =find(regEx, source);
		HashMap<String, ArrayList<StringList>> matches = new HashMap<String, ArrayList<StringList>>();
		for(int i =0;i<match.size();i++){
			for(int j =0;j<match.get(i).data.size();j++){
				if(!(matches.containsKey(match.get(i).data.get(j).line))){
					ArrayList<StringList> temp = new ArrayList<StringList>();
					temp.add(match.get(i));
					matches.put(match.get(i).data.get(j).line, temp);
				} else {
					matches.get(match.get(i).data.get(j).line).add(match.get(i));
				}
			}
		}

		Scanner input;
		String stringBuffer ="";
		try{
			// Open the file that is the first 
			// command line parameter
			FileInputStream fstream = new FileInputStream(source);
			// Get the object of DataInputStream
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			//Read File Line By Line
			int line = 0;
			while ((strLine = br.readLine()) != null)   {
				line++;
				if(matches.containsKey(""+line)){
					PriorityQueue<String> startIndex = new PriorityQueue<String>();
					PriorityQueue<String> endIndex = new PriorityQueue<String>();
					for(StringList a:matches.get(""+line)){
						for(Data b:a.data){
							startIndex.add(b.startIndex);
							endIndex.add(b.endIndex);
						}
					}

					for(int i = 0;i<strLine.length();i++){
						if(startIndex.peek().equals(""+i)){
							stringBuffer=stringBuffer+replaceWith;
							startIndex.poll();
							i=Integer.parseInt(endIndex.poll());
						} else {
							stringBuffer=stringBuffer+strLine.charAt(i);
						}
					}
				} else {
					input = new Scanner(strLine);
					boolean check = false;
					while(input.hasNext()) {
						if(check){
							stringBuffer=stringBuffer+" ";

						} else {
							check = true;
						}
						stringBuffer=stringBuffer+input.next();
					}
				}

				stringBuffer=stringBuffer+"\n";
			}

			//Close the input stream
			in.close();
		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}


		try{
			// Create file 
			File name = new File(destination);
			if(name.exists()){
				name.delete();
			}
			FileWriter fstream = new FileWriter(name,true);

			BufferedWriter output = new BufferedWriter(fstream);

			for(int i = 0;i<stringBuffer.length();i++){
				if((int)stringBuffer.charAt(i)=='\n'){
					output.newLine();
				} else{
					output.write(""+stringBuffer.charAt(i));
				}


			}
			//Close the output stream
			output.close();
		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}


	}

}
